/*

--1--
const作用
A:定义常量--定义时初始化，此后无法更改
B:修饰形参--表示该形参的值在该函数中是不可以修改的
C:修饰指针--指针常量--指针类型的常量(int *const p)--指针指向的地址不能修改，地址指向的内容可以修改
         --常量指针--指向"常量"的指针(const int *p,int const *p)
         --指针指向的地址可以修改，地址指向的内容不能修改-如char*
E:修饰函数的返回值，一般用于修饰指针，函数返回值将不能被修改，而且只能被const修饰的同类型常量接受
C++扩展:
F:修饰成员函数--该成员函数对成员属性只有访问权没有修改权
              --如果要修改属性则需要在成员变量前加mutable声明
G:修饰类的对象--该对象只能调用类中的被const修饰的函数，无法调用非const函数
              --对于非mutable成员，只有访问权没有修改权
H:修饰类的成员变量，只能在构造函数的初始化列表中对其进行初始化，初始化之后无法再修改
const修饰的事物会受到一定的保护，可以预防意外的变动，能提高程序的健壮性



--2--
const与#define相比有什么不同
A:const常量有数据类型，而宏常量没有数据类型,编译器可以对前者进行类型安全检查
        --而对后者只进行字符替换，没有安全检查，并且在字符替换中可能会达不到预期效果甚至出错
B:有些集成化的调试工具可以对const常量进行调试，但是不能对宏常量进行调试


--3--
static作用
A:定义静态局部变量，变量加上static声明后，内存分配在全局区，生命周期增长至整个程序结束，而且不改变作用域
                --编译器执行到该变量的声明时，初始化一次，以后不再初始化
B:修饰全局变量，修改全局变量的作用域为当前源文件内，其他文件将无法再引用这个全局变量
C:定义静态函数，修改该函数的作用域，仅限于当前源文件，无法外部源文件调用
             --其他源文件中也可以定义与该函数名相同的静态函数，不再发生重命名错误
             --静态函数会被自动分配在一个一直使用的存储区，直到程序结束才从内存消失
             --避免调用函数时压栈出栈，速度快很多
C++扩展:
D:修饰类成员变量，使其成为类的静态成员变量，所有对象共享一个该成员变量
                --不能在构造函数初始化,只能在类外初始化
                --可以通过类名直接调用，无需创建具体的对象
E:修饰类成员函数，使其成为静态成员函数，可以通过类名直接调用，无需创建具体的对象
                --只能调用和访问类中的静态成员函数和静态成员，无法访问非静态成员
F:


--11--
new与malloc区别
A:new按照数据类型进行分配内存，malloc按照需求大小分配内存
B:new不仅分配一段内存，而且会调用构造函数，但是malloc则不会
C:new返回的是相应数据类型的指针，而malloc返回的是void*，因此malloc的返回值一般都需要进行类型转化
D:new是一个操作符可以重载，malloc是一个库函数
E:new分配的内存要用delete销毁，malloc要用free来销毁；delete销毁会调用对象的析构函数，而free则不会
F:malloc分配的内存不够的时候，可以用realloc扩容
G:new如果分配失败了会抛出bad_malloc的异常，而malloc失败了会返回NULL


--12--
指针和引用的区别
A:指针保存的是所指对象的地址，引用是所指对象的别名，指针需要通过解引用间接访问，而引用是直接访问
B:指针可以改变地址，从而改变所指的对象，而引用必须从一而终
C:引用在定义的时候必须初始化，而指针则不需要
D:指针是实体的，是一个变量，占据一定的内存，引用不是一个变量，不占据内存


--13--
内存对齐
A:从0位置开始存储
B:变量存储的起始位置是该变量大小的整数倍
C:结构体总的大小是其最大元素的整数倍，不足的后面要补齐
D:结构体中包含结构体，从结构体中最大元素的整数倍开始存
E:如果加入pragma pack(n) ，取n和变量自身大小较小的一个


--14--
C++四种类型转换
A:const_cast用于将const变量转为非const
B:static_cast用于各种隐式转换，非const转const，void*转指针等
            --也能用于多态想上转化，如果向下转能成功但是不安全，结果未知
C:dynamic_cast用于动态类型转换，只能用于含有虚函数的类，用于类层次间的向上和向下转化
            --只能转指针或引用，向下转化时，如果是非法的对于指针返回NULL，对于引用抛异常
D:reinterpret_cast几乎什么都可以转，比如将int转指针，可能会出问题，尽量少用
E:C的强制转换表面上看起来功能强大什么都能转，但是转化不够明确，不能进行错误检查，容易出错


--15--
内联函数的优点，和宏定义函数的区别
A:宏定义在预编译的时候就会进行宏替换
B:内联函数在编译阶段，在调用内联函数的地方进行替换，减少了函数的调用过程，但是使得编译文件变大
  --因此，内联函数适合简单函数，对于复杂函数，即使定义了内联函数编译器可能也不会按照内联的方式进行编译
C:内联函数相比宏定义更安全，内联函数可以检查参数，而宏定义只是简单的文本替换


--16--
C++内存管理
A:stack-栈区--存放局部变量，可读可写，代码块执行完后，其中局部变量占据的内存就会被自动释放
B:共享映射区--所有程序共享一个物理地址，存放动态库、手动开辟的共享内存
C:heap-堆区--由程序员通过系统调用如new、malloc开辟的内存空间
           --可读可写，一旦开辟，就会一直存在，直到你手动销毁
D:.rodata-常量区-只读段，存放程序中的只读数据如字符串常量，一直存在，随进程持续性
E:全局区--.data--存放已经初始化的全局变量和静态变量
        --.bss--存放没有初始化的全局变量和静态变量
        --可读可写，这段内存在进程运行期间，一直存在，随进程持续性
F:.text-代码段--只读并且共享，存放二进制的代码段，这段内存在进程运行期间,不会释放的，随进程持续性


--17--
C++多态的实现、虚函数作用
A:静态多态--通过函数重载和模板技术实现，在编译的时候确定
B:动态多态--通过虚函数和继承关系来实现，执行动态绑定，在运行的时候确定
         --动态多态的条件
         -虚函数
         -一个基类的指针或引用指向派生类的对象
C:虚函数作用--实现多态



--18--
虚函数表
虚函数表是一个指针链表，编译期建立，存储类中的虚函数，一个类的所有对象共享一个虚函数表
当类中定义了虚函数的时候，编译器会给这个类添加一个虚函数表，创建对象时自动包含有一个虚函数表指针
该指针是在类创建的时候也就是运行期创建的，指向该类的虚函数表，如果当前类重写了父类的虚函数
编译器会在虚函数表中，用当前重写的虚函数指针替换掉表中父类的虚函数指针


--19--
虚函数多态的实现
A:存在虚函数以及继承关系
B:父类的指针或引用指向子类的对象
因为指向的是子类的对象，所以访问到的是子类的虚函数表，因为子类重写了父类的虚函数
编译器会在子类的虚函数表中，替换掉父类的虚函数指针，所以虽然是父类的指针或引用
但访问的是子类的虚函数表，调用的函数自然也是子类中重写的虚函数
若子类中没有重写，调用的就是原本继承过来的父类虚函数


--20--
虚析构函数作用
A:动态多态时，防止父类的资源没有释放导致内存泄露


--21--
纯虚函数
A:只有声明，没有定义
B:该类成为抽象类，不能实例化
C:子类必须重写所有的纯虚函数才能实例化
D:用于对外接口，如COM组件、注册回调函数


--22--
C++中struct和class的区别
A:如果不明确指定，来自class的继承按照private继承处理，来自struct的继承按照public继承处理
B:class的成员默认是private权限，struct默认是public权限


--23--
C++ 11标准
A:std::auto 参数自动推导。std::decltype推导表达式类型，会保留引用和cv属性
B:右值引用，std::move移动语义资源的控制权移交，左值转化成右值
C:Lambad表达式 std::function、std::bind 函数对象
D:可以使用using代替typedef，using Task = std::function<void()>;
E:模板的右尖括号之前是不允许两个右尖括号出现的，会被认为是右移操作符
F:函数模板的默认模板参数，template <typename T, typename U=int>
G:std::unique_ptr、shared_ptr、weak_ptr NULL与 nullptr
H:std::thread std::mutex std::lock std::atomic std::call_once std::condition_variable
I:std::future std::promise std::packaged_task std::async


--24--
Hash冲突处理
A:开放地址，线性探测、二次探测、随机探测
B:拉链法，给每一个hash值建立一个链表。内存利用率高，查询慢，要额外交地址税，频繁申请内存
C:再哈希，一个hash函数冲突，多次换直到一个不冲突的hash函数
D:建立公共溢出区，冲突的元素放入公共溢出区


--25--
C++手撕单例，静态函数没有this指针，所以不能访问普通成员函数
静态函数和静态成员的作用域是处于类的内部，可以调用私有和保护权限的函数，如私有构造
懒汉式:需要手动确定线程安全
class singleton
{
public:
    static singleton* getsingleton()
    {
        if(!singleton_ptr) // 懒汉式，需要用到时才创建
            singleton_ptr = new singleton;
        return singleton_ptr;
    }
private:
    singleton() {} // 私有构造，使得外部无法调用
    static singleton* singleton_ptr; // 私有静态，保证一份

}; // class singleton end
singleton* singleton::singleton_ptr = nullptr; // 需要用到时才创建，初始化不创建

饿汉式:自动为线程安全，无需手动设置线程安全
class singleton
{
public:
    static singleton& getsingleton() // 作为全局变量自动创建
    { return singleton_reference; }
private:
    singleton() {}
    static singleton singleton_reference;

}; // class singleton end
singleton singleton::singleton_reference; // 饿汉式，一开始就自动创建，线程安全

*/